#include "gtest/gtest.h"

#include "rocksdb/db.h"
#include "rocksdb/options.h"

#include "Helper.h"

using namespace std;
using namespace rocksdb;


class ColumnFamilyTest : public testing::Test {
public:
    bool isExist(std::string cfName){
        std::vector<std::string> cfs;
        auto && s = rocksdb::DB::ListColumnFamilies(DBOptions(), dbname, &cfs);
        if(!s.ok()) std::cout << s.ToString() << std::endl;

        for( auto && name : cfs){
            if(name == cfName){
                return true;
            }
        }
        return false;
    }
protected:
    const std::string dbname = "./test-cf.db";
    Helper helper;
};
TEST_F(ColumnFamilyTest, testList){
    //NOTE:!!!!! assert the db is exist 
    std::vector<ColumnFamilyHandle*> handles;
    auto db = helper.createDbCfs(dbname, handles);
    db.reset();

    // if db is not exist :  ListColumnFamilies return failed
    rocksdb::DBOptions dbOptions;
    std::vector<std::string> cfs;
    auto && s = rocksdb::DB::ListColumnFamilies(dbOptions, dbname, &cfs);
    ASSERT_TRUE(s.ok());
    ASSERT_TRUE(cfs.size() >= 1);
}

//isExist
TEST_F(ColumnFamilyTest, testIsExist){
    //NOTE:!!!!! assert the db is exist
    std::vector<ColumnFamilyHandle*> handles;
    auto db = helper.createDbCfs(dbname, handles);
    db.reset();

    // if db is not exist :  ListColumnFamilies return failed
    const std::string expect = "default";
    ASSERT_TRUE(isExist(expect));
}

//create 
TEST_F(ColumnFamilyTest, testCreate){
    std::vector<ColumnFamilyHandle*> handles;
    auto db = helper.createDbCfs(dbname, handles);
    
    const std::string newCfName = "meta";
    if(!isExist(newCfName)){
        rocksdb::ColumnFamilyHandle * cfHandle;
        auto s = db->CreateColumnFamily(ColumnFamilyOptions(), newCfName,  &cfHandle);
        if(!s.ok()) std::cout << s.ToString() << std::endl;
        ASSERT_TRUE(s.ok());

        s = db->DestroyColumnFamilyHandle(cfHandle); //Close Handle
        ASSERT_TRUE(s.ok());
        std::cout << "create :" << newCfName << " OK" << std::endl;
    }
    ASSERT_TRUE(isExist(newCfName));
}
//create && drop
TEST_F(ColumnFamilyTest, testDrop){
    std::vector<ColumnFamilyHandle*> handles;
    auto db = helper.createDbCfs(dbname, handles);

    const std::string newCfName = "uselessCf";
    if(!isExist(newCfName)){
        rocksdb::ColumnFamilyHandle * cfHandle;
        auto s = db->CreateColumnFamily(ColumnFamilyOptions(), newCfName,  &cfHandle);
        if(!s.ok()) std::cout << s.ToString() << std::endl;
        ASSERT_TRUE(s.ok());

        s = db->DropColumnFamily(cfHandle);
        if(!s.ok()) std::cout << s.ToString() << std::endl;
        ASSERT_TRUE(s.ok());

        s = db->DestroyColumnFamilyHandle(cfHandle);
        ASSERT_TRUE(s.ok());
        std::cout << "create :" << newCfName << " OK" << std::endl;
    }
    ASSERT_TRUE(!isExist(newCfName));
}

//get 
TEST_F(ColumnFamilyTest, testGet){
    std::vector<ColumnFamilyHandle*> handles;
    auto db = helper.createDbCfs(dbname, handles);

    void * actualHandle = nullptr;
    const std::string expect = "default";
    for(auto * h : handles){
        if(h != nullptr && expect == h->GetName()){
            actualHandle = h;
            break;
        }
    }
    ASSERT_TRUE(actualHandle != nullptr);
}
